﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ProjectPenguin.Cards;
using NSGeo.Geometry;
using ProjectPenguin.Cards.ProcessorCardHelpers;

namespace ProjectSnake
{
    class Snake
    {
        public List<Point3d> Trace { get; private set; } // 转弯点。有序序列。
        public Point3d Head { get; private set; } // 头部
        public int Length { get; set; }  // 长度
        public int Velocity { get; set; } // 速度
        public PolylineCurve Body
        {
            get
            {
                var temp_Trace = new List<Point3d>(Trace);
                if (temp_Trace.Count == 0) return null;
                if (temp_Trace.Last() != Head) temp_Trace.Add(Head); // 临时增加head，因为head一直在变
                if (temp_Trace.Count < 2) return null;

                var polylinecurve = new PolylineCurve(temp_Trace);
                var divided_ts = polylinecurve.DivideByLength(polylinecurve.GetLength() - Length, false);
                if (divided_ts.Length == 0) return polylinecurve;
                else return (PolylineCurve)polylinecurve.Trim(divided_ts[0], polylinecurve.Domain[1]);
            }
        }

        public Snake()
        {
            Trace = new List<Point3d>();
        }

        public Snake(Line line)
        {
            Trace = new List<Point3d> { line.From };
            Head = line.To;
            Length = (int)line.Length;
            Velocity = 1;
        }

        public void Move(Point3d direction) // 方向
        {
            Head += direction * Velocity;
        }

        public void AddHeadToTrace() // 方向
        {
            Trace.Add(Head);
        }
    }

    public class SnakeCard : ProcessorCardBase
    {
        public SnakeCard() : base("snake", "snake", "snake", "GamerDeck", "ProjectSnake") { }
        static Guid _guid = Guid.Parse("{E08A948A-90C0-4A31-B91F-F2A90436BE34}");
        public override Guid CardGuid => _guid;

        // static fields
        private static Snake SolidSnake = new Snake();
        public static int Length { get { return SolidSnake.Length; } set { SolidSnake.Length = value; } }

        public static bool Collided = false;

        protected override void AddInputSideDataCards(IDataCardEmbedmentHelper helper)
        {
            helper.AddWellKnownTypeOfDataCard(typeof(bool), "重置", "重置", "重置蛇的位置", ProjectPenguin.Cards.Enums.DataProcessingMode.OneByOne);
            helper.AddWellKnownTypeOfDataCard(typeof(Line), "初始", "初始", "初始蛇的状态", ProjectPenguin.Cards.Enums.DataProcessingMode.OneByOne);
            helper.AddWellKnownTypeOfDataCard(typeof(bool), "转向", "转向", "是否发生转向", ProjectPenguin.Cards.Enums.DataProcessingMode.OneByOne);
            helper.AddWellKnownTypeOfDataCard(typeof(Point3d), "方向", "方向", "输入的蛇的方向", ProjectPenguin.Cards.Enums.DataProcessingMode.OneByOne);
            helper.AddWellKnownTypeOfDataCard(typeof(bool), "运行", "运行", "运行状态", ProjectPenguin.Cards.Enums.DataProcessingMode.OneByOne);
        }

        protected override void AddOutputSideDataCards(IDataCardEmbedmentHelper helper)
        {
            helper.AddWellKnownTypeOfDataCard(typeof(Polyline), "蛇", "蛇", "蛇", ProjectPenguin.Cards.Enums.DataProcessingMode.OneByOne);
            //helper.AddWellKnownTypeOfDataCard(typeof(object), "This", "This", "This", ProjectPenguin.Cards.Enums.DataProcessingMode.OneByOne);
        }

        /// <summary>
        /// 卡片丢出来就已经完成实例化了，而我们只能通过build输入参数
        /// Build里是脚本，描述怎么使用这个实例对象
        /// 所以只能在build冲重新构造一次
        /// </summary>
        /// <param name="idd">对应卡片所有输入数据的容器</param>
        public override void Build(IDataDelivery idd)
        {
            bool reset = false;
            Line init_line = new Line();
            // 运行时的方向数据
            bool if_diverse = true;
            Point3d direction = new Point3d(); // 用于计算head的下一个位置
            // 时间相关，触发运行
            bool move = false;

            if (!idd.GetDataItem(0, ref reset)) return;
            if (!idd.GetDataItem(1, ref init_line)) return;
            if (!idd.GetDataItem(2, ref if_diverse)) return;
            if (!idd.GetDataItem(3, ref direction)) return;
            if (!idd.GetDataItem(4, ref move)) return;

            // 如果传入了true，重置蛇的数据
            if (reset)
            {
                SolidSnake = new Snake(init_line);
                Collided = false;
            }

            // 转向捕捉，把当前的head加入trace
            if (if_diverse)
            {
                SolidSnake.AddHeadToTrace();
            }

            // 刷新告诉可以前进
            if (move && !Collided)
            {
                SolidSnake.Move(direction);
            }

            // 
            if (SolidSnake.Body == null)
                idd.SetDataItem(0, null);
            else
            {
                var out_snake = SolidSnake.Body.ToPolyline(); // 测试用
                //idd.SetDataItem(0, new PolylineCurve(out_snake));
                idd.SetDataItem(0, out_snake);
            }
        }
    }


    public class SnakeCollidedCard : ProcessorCardBase
    {
        public SnakeCollidedCard() : base("静默-蛇撞墙", "静默-蛇撞墙", "静默触发-蛇撞墙", "GamerDeck", "ProjectSnake") { }
        static Guid _guid = Guid.Parse("{AA2DE29D-3F39-4EAC-9117-D69AE70B438E}");
        public override Guid CardGuid => _guid;
        protected override void AddInputSideDataCards(IDataCardEmbedmentHelper helper)
        {
            helper.AddWellKnownTypeOfDataCard(typeof(bool), "bool", "bool", "bool", ProjectPenguin.Cards.Enums.DataProcessingMode.OneByOne);
        }
        protected override void AddOutputSideDataCards(IDataCardEmbedmentHelper helper){}
        public override void Build(IDataDelivery idd)
        {
            bool trigger = false;
            if (!idd.GetDataItem(0, ref trigger)) return;

            // 暗改
            if (trigger) SnakeCard.Collided = true;
        }
    }

    public class SnakeSelfCollidedCard : ProcessorCardBase
    {
        public SnakeSelfCollidedCard() : base("蛇撞自己", "蛇撞自己", "蛇撞自己", "GamerDeck", "ProjectSnake") { }
        static Guid _guid = Guid.Parse("{AFDDE5C0-095D-42A6-8A79-236F86E82A53}");
        public override Guid CardGuid => _guid;
        protected override void AddInputSideDataCards(IDataCardEmbedmentHelper helper)
        {
            helper.AddWellKnownTypeOfDataCard(typeof(Polyline), "蛇", "蛇", "蛇", ProjectPenguin.Cards.Enums.DataProcessingMode.OneByOne);
        }
        protected override void AddOutputSideDataCards(IDataCardEmbedmentHelper helper) 
        {
            helper.AddWellKnownTypeOfDataCard(typeof(bool), "bool", "bool", "bool", ProjectPenguin.Cards.Enums.DataProcessingMode.OneByOne);
        }

        public override void Build(IDataDelivery idd)
        {
            Polyline pl = new Polyline();
            if (!idd.GetDataItem(0, ref pl)|| pl==null) return;

            Polyline temp = pl.Duplicate();

            var head = temp[pl.Count-1];
            temp.RemoveAt(pl.Count - 1);

            idd.SetDataItem(0, false);
            if (temp.ClosestPoint(head).DistanceTo(head) < 1e-8) idd.SetDataItem(0, true);
        }
    }
}
